package dgo.tilemap;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Enumeration;
import starruby.Texture;

public class Map {
      // x and y should be less than 2^BIT
      public final byte BIT = 8;
      public final int MIN = Integer.MIN_VALUE;
      public final byte LAYER_NUM = 2;
      public final byte FRAME_NUM = 4;
      public final byte ANIME_TIME = 10;
      public final byte EX_GRID = 1;
      
      public int frameNo;
      public int baseX, baseY;
      public byte gridWidth, gridHeight, xCount, yCount, showXCount, showYCount;
      public byte[][] collisionData;
      public PaletChip[][][] layers;
      private Hashtable _objectCollisions, _objects;
      private byte _timer = 0;
      private Texture _panoramaTexture;
      public Map(byte xCount, byte yCount, PaletChip[][][] layers, byte showXCount, byte showYCount, byte gridWidth, byte gridHeight, byte[][] collisionData, Texture panoramaTexture){
        this.gridWidth = gridWidth;
        this.gridHeight = gridHeight;
        this.xCount = xCount;
        this.yCount = yCount;
        this.showXCount = showXCount;
        this.showYCount = showYCount;
        this.collisionData = collisionData;
        //System.out.println(collisionData);
        this.layers = layers;
        _objectCollisions = new Hashtable();
        _objects = new Hashtable();
        _panoramaTexture = panoramaTexture;
        baseX = 0;
        baseY = 0;
      }

      public int getKey(int x, int y){
        return x + (y << BIT);
      }
            
      public byte getChipCollision(int x, int y){
        return collisionData[x][y];
      }
      
      public MapCharacter getObjectCollision(MapCharacter character, int x, int y){
        Integer key = new Integer(getKey(x, y));
        Stack s = (Stack)_objects.get(key);
        
        MapCharacter t = null;
        if(s != null){
          Enumeration e = s.elements();
          while (e.hasMoreElements()) {
            t = (MapCharacter)e.nextElement();
            if(t.layer == character.layer){ break; }
            t = null;
          }
        }

        if(t != null){
          return t;
        }else{
          return null;
        }
      }

      public void setObjectCollision(int x, int y, byte value){
        Integer key = new Integer(getKey(x, y));
        _objectCollisions.put(key, new Byte(value));
      }

      public void resetObjectCollisions(){
        _objectCollisions.clear();
      }

      public MapCharacter getCharacter(int x, int y){
        Stack s = getCharacters(x, y);
        if(s != null){
          return (MapCharacter)s.peek();
        }else{
          return null;
        }
      }

       public Stack getCharacters(int x, int y){
        Integer key = new Integer(getKey(x, y));
        return (Stack)(_objects.get(key));
      }
       
      public void setCharacter(int x, int y, MapCharacter obj){
        Integer key = new Integer(getKey(x, y));
        if(_objects.get(key) == null){
          _objects.put(key, new Stack());
        }
        
        ((Stack)_objects.get(key)).push(obj);
      }
      
      public void removeCharacter(int x, int y, MapCharacter character){
        Integer key = new Integer(getKey(x, y));
        if(_objects.get(key) != null){
         ((Stack)_objects.get(key)).removeElement(character);
        }
      }
      
      public void resetCharacters(){
        _objects.clear();
      }
        
      // Map
      public int width(){
        return this.gridWidth * this.xCount;
      }

      public int height(){
        return this.gridHeight * this.yCount;
      }
      
      public int showWidth(){
        return this.gridWidth * this.showXCount;
      }
          
      public int showHeight(){
        return this.gridHeight * this.showYCount;
      }

      public boolean isObstacle(MapCharacter character, int x, int y, int dir){
        
        if((x >= collisionData.length)||(x < 0)){ return true; }
        if((y >= collisionData[x].length)||(y < 0)){ return true; }
        MapCharacter target = getObjectCollision(character, x, y);
        int data = 0;
        if(target == null || target.passTile){
           if(character.passTile){return false;}
           data = collisionData[x][y];
        }else{
          data = CollisionType.ALL;
          target.isTouched(character);
          if(character.passCharacters || target.passCharacters) return false;
        }

        return (data & dir) != 0;
      }

      public void update(){
        _timer += 1;
        if(_timer >= ANIME_TIME){
          _timer = 0;
          frameNo += 1;
          if(frameNo >= FRAME_NUM){
            frameNo = 0;
          }
        }
      }
      
      public void renderPanorama(Texture s){
        if(_panoramaTexture != null){
          s.renderTexture(_panoramaTexture, 0, 0);
        }
      }
      public void render(Texture s, int layerNo){
        int dx = this.baseX % this.gridWidth;
        int dy = this.baseY % this.gridHeight;
        
        int sx = this.baseX / this.gridWidth;
        int sy = this.baseY / this.gridHeight;
        
        int ex = sx + this.showXCount;
        int ey = sy + this.showYCount;
        
        if(ex >= this.xCount) ex = this.xCount - 1;
        if(ey >= this.yCount) ey = this.yCount - 1;
        
        for(int i = sx; i <= ex; i++){
          for(int j = sy; j <= ey; j++){
            for(int k = 0; k < layers.length; k++){
              PaletChip p = layers[k][i][j];
              if(p != null && p.priority == layerNo){
                p.render(s, i - sx, j - sy, dx, dy, frameNo);
              }
            }
          } 
        }   
        
        //layers[layerNo][i].render(s, i % xCount, i / xCount, 0, 0, frameNo);
      }
}
